home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NeXTSTEP 3.3 (Developer)…68k, x86, SPARC, PA-RISC]
/
NeXTSTEP 3.3 Dev Intel.iso
/
NextDeveloper
/
Source
/
GNU
/
cctools
/
as
/
hppa.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-28
|
46KB
|
1,830 lines
/* hppa.c -- Assemble for the HP-PA
Copyright (C) 1989 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
HP PA-RISC support was contributed by the Center for Software Science
at the University of Utah.
*/
/* HP-PA support for Mach-O ... USV */
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <mach-o/hppa/reloc.h>
#define HPPA_RELOC_12BRANCH (127) /* only used internal in here */
#include "obstack.h"
#include "hppa-opcode.h"
#include "as.h"
#include "frags.h"
#include "flonum.h"
#include "hash.h"
#include "md.h"
#include "symbols.h"
#include "hppa-aux.h"
#include "messages.h"
#include "stuff/hppa.h"
/*
* These are the default cputype and cpusubtype for the hppa architecture.
*/
const cpu_type_t md_cputype = CPU_TYPE_HPPA;
cpu_subtype_t md_cpusubtype = CPU_SUBTYPE_HPPA_ALL;
/* This is the byte sex for the hppa architecture */
const enum byte_sex md_target_byte_sex = BIG_ENDIAN_BYTE_SEX;
/* These characters start a comment anywhere on the line */
const char md_comment_chars[] = ";";
/* These characters only start a comment at the beginning of a line */
const char md_line_comment_chars[] = "#";
/*
* These characters can be used to separate mantissa decimal digits from
* exponent decimal digits in floating point numbers.
*/
const char md_EXP_CHARS[] = "eE";
/*
* The characters after a leading 0 that means this number is a floating point
* constant as in 0f123.456 or 0d1.234E-12 (see md_EXP_CHARS above).
*/
const char md_FLT_CHARS[] = "dDfF";
/*
* This is the machine dependent pseudo opcode table for this target machine.
*/
const pseudo_typeS md_pseudo_table[] =
{
{0} /* end of table marker */
};
static int found_jbsr = 0;
static char *toP;
const relax_typeS md_relax_table[] = { 0 };
/* handle of the OPCODE hash table */
static struct hash_control *op_hash = NULL;
struct pa_it the_insn; /* this structure is defined in pa-aux.h */
char *expr_end;
static void pa_ip(
char *str);
static int parse_L_or_R(
char *str);
static unsigned long parse_completer_with_cache_control_hint(
char **s, /* Note : the function changes '*s' */
int option, /* option = 0 for store instruction */
/* option = 1 for load and clear instruction */
char completer);/* 'c' or 'C' */
static unsigned long parse_cache_control_hint(
char **s, /* Note : the function changes '*s' */
int option); /* option = 0 for store instruction */
/* option = 1 for load and clear instruction */
/* This function is called once, at assembler startup time. It should
set up all the tables, etc. that the MD part of the assembler will need. */
void
md_begin(
void)
{
register char *retval = NULL;
int lose = 0;
register unsigned int i = 0;
op_hash = hash_new();
if (op_hash == NULL)
as_fatal("Virtual memory exhausted");
while (i < NUMOPCODES) {
const char *name = pa_opcodes[i].name;
retval = hash_insert(op_hash, (char *)name,
(char *)&pa_opcodes[i]);
if(retval != NULL && *retval != '\0') {
as_fatal("Internal error: can't hash `%s': %s\n",
pa_opcodes[i].name, retval);
lose = 1;
}
++i;
}
if (lose)
as_fatal ("Broken assembler. No assembly attempted.");
}
void
md_end(
void)
{
return;
}
void
md_assemble(
char *str)
{
assert(str);
pa_ip(str);
if (!found_jbsr)
toP = frag_more(4);
else
found_jbsr = 0;
/* put out the opcode */
md_number_to_chars(toP, the_insn.opcode, 4);
/* put out the symbol-dependent stuff */
if (the_insn.reloc != NO_RELOC) {
fix_new(frag_now, /* which frag */
(toP - frag_now->fr_literal), /* where */
4, /* size */
the_insn.exp.X_add_symbol,
the_insn.exp.X_subtract_symbol,
the_insn.exp.X_add_number, /* offset */
the_insn.pcrel,
the_insn.pcrel_reloc,
the_insn.reloc);
}
}
static
void
pa_ip(
char *str)
{
char *s;
const char *args;
char c;
unsigned long i;
struct pa_opcode *insn;
char *argsStart;
unsigned long opcode;
int match = FALSE;
int comma = 0;
int reg,reg1,reg2,s2,s3;
unsigned int im21,im14,im11,im5;
int m,a,u,f;
int cmpltr,nullif, flag;
int sfu, cond;
char *name;
char *save_s;
#ifdef PA_DEBUG
fprintf(stderr,"STATEMENT: \"%s\"\n",str);
#endif
for (s = str; isupper(*s) || islower(*s) || (*s >= '0' && *s <= '3'); ++s)
;
switch (*s) {
case '\0':
break;
case ',':
comma = 1;
/*FALLTHROUGH*/
case ' ':
*s++ = '\0';
break;
default:
as_bad("Unknown opcode: `%s'", str);
exit(1);
}
save_s = str;
while ( *save_s ) {
if ( isupper(*save_s) )
*save_s = tolower(*save_s);
save_s++;
}
if ((insn = (struct pa_opcode *) hash_find(op_hash, str)) == NULL) {
as_bad("Unknown opcode: `%s'", str);
return;
}
if (comma) {
*--s = ',';
}
argsStart = s;
for (;;) {
opcode = insn->match;
memset(&the_insn, '\0', sizeof(the_insn));
the_insn.reloc = NO_RELOC; /* USV */
/*
* Build the opcode, checking as we go to make
* sure that the operands match
*/
for (args = insn->args; ; ++args) {
switch (*args) {
case '\0': /* end of args */
if (*s == '\0') {
match = TRUE;
}
break;
case '(': /* these must match exactly */
case ')':
case ',':
case ' ':
if (*s++ == *args)
continue;
break;
case 'b': /* 5 bit register field at 10 */
reg = pa_parse_number(&s);
if ( reg < 32 && reg >= 0 ) {
opcode |= reg << 21;
continue;
}
break;
case 'x': /* 5 bit register field at 15 */
reg = pa_parse_number(&s);
if ( reg < 32 && reg >= 0 ) {
opcode |= reg << 16;
continue;
}
break;
case 't': /* 5 bit register field at 31 */
reg = pa_parse_number(&s);
if ( reg < 32 && reg >= 0 ) {
opcode |= reg;
continue;
}
break;
case 'T': /* 5 bit field length at 31 (encoded as 32-T) */
/*
reg = pa_parse_number(&s);
*/
getAbsoluteExpression(s);
if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
reg = the_insn.exp.X_add_number;
if ( reg <= 32 && reg > 0 ) {
opcode |= 32 - reg;
s = expr_end;
continue;
}
}
break;
case '5': /* 5 bit immediate at 15 */
getAbsoluteExpression(s);
/** PJH: The following 2 calls to as_bad() might eventually **/
/** want to end up as as_warn(). **/
if ( the_insn.exp.X_add_number > 15 ) {
as_bad("5 bit immediate: %ld > 15. Set to 15",
the_insn.exp.X_add_number);
the_insn.exp.X_add_number = 15;
}
else if ( the_insn.exp.X_add_number < -16 ) {
as_bad("5 bit immediate: %ld < -16. Set to -16",
the_insn.exp.X_add_number);
the_insn.exp.X_add_number = -16;
}
im5 = low_sign_unext(evaluateAbsolute(
the_insn.exp,0),5);
opcode |= ( im5 << 16 );
s = expr_end;
continue;
case 's': /* 2 bit space identifier at 17 */
s2 = pa_parse_number(&s);
if ( s2 < 4 && s2 >= 0 ) {
opcode |= s2 << 14;
continue;
}
break;
case 'S': /* 3 bit space identifier at 18 */
s3 = pa_parse_number(&s);
if ( s3 < 8 && s3 >= 0 ) {
s3 = dis_assemble_3(s3);
opcode |= s3 << 13;
continue;
}
break;
case 'c': /* indexed load completer. */
i = m = u = 0;
while ( *s == ',' && i < 2 ) {
s++;
if ( strncasecmp(s,"sm",2) == 0 ) {
m = u = 1;
s++;
i++;
}
else if ( strncasecmp(s,"m",1) == 0 )
m = 1;
else if ( strncasecmp(s,"s",1) == 0 )
u = 1;
else
as_bad("Unrecognized Indexed Load"
"Completer...assuming 0");
s++;
i++;
}
if ( i > 2 )
as_bad("Illegal Indexed Load Completer Syntax..."
"extras ignored");
while ( *s == ' ' || *s == '\t' )
s++;
opcode |= m << 5;
opcode |= u << 13;
continue;
case 'C': /* short load and store completer */
m = a = 0;
if ( *s == ',' ) {
s++;
if ( strncasecmp(s,"ma",2) == 0 ) {
a = 0;
m = 1;
}
else if ( strncasecmp(s,"mb",2) == 0 ) {
m = a = 1;
}
else
as_bad("Unrecognized Indexed Load Completer"
"...assuming 0");
s += 2;
}
while ( *s == ' ' || *s == '\t' )
s++;
opcode |= m << 5;
opcode |= a << 13;
continue;
/* bug #41317 .... umeshv@NeXT.com
* Fri Jul 22 09:43:46 PDT 1994
*
* Modified to parse 'cache control hints'
*
* These parse ",cc" and encode "cc" in 2 bits at 20,
* where "cc" encoding is as given in Tables 5-8, 5-9.
* Refer to 'PA-RISC 1.1 Architecture and Instruction Set
* Reference Manual, Second Edition' for the tables.
*/
case 'Y': /* Store Bytes Short completer */
/* with cache control hints */
{
unsigned long result = (unsigned long)0UL;
i = m = a = 0;
while ( *s == ',' && i < 3 ) {
s++;
if ( strncasecmp(s,"m",1) == 0 )
m = 1;
else if ( strncasecmp(s,"b",1) == 0 &&
(strncasecmp((s+1),"c",1) != 0) )
a = 0;
else if ( strncasecmp(s,"e",1) == 0 )
a = 1;
else if ( strncmp(s,",",1) == 0 ) /* no completer */
result |= parse_cache_control_hint(&s, 0);
else if ( (strncasecmp(s,"c",1) == 0) ||
(strncasecmp(s,"b",1) == 0) ) {/* just 1 completer */
s--;
result |= parse_cache_control_hint(&s, 0);
}
else
as_bad("Unrecognized Store Bytes Short"
"Completer with cache control hints"
" ...assuming 0");
if (result == (unsigned long)0UL)
s++;
i++;
}
/** if ( i >= 2 ) **/
if ( i > 3 )
as_bad("Illegal Store Bytes Short Completer "
"with cache control hints ... extras ignored");
while ( *s == ' ' || *s == '\t' ) /* skip to next operand */
s++;
opcode |= result;
opcode |= m << 5;
opcode |= a << 13;
continue;
}
case '<': /* non-negated compare/subtract conditions. */
cmpltr = pa_parse_nonneg_cmpsub_cmpltr(&s);
if ( cmpltr < 0 ) {
as_bad("Unrecognized Compare/Subtract Condition: %c",*s);
cmpltr = 0;
}
opcode |= cmpltr << 13;
continue;
case '?': /* negated or non-negated cmp/sub conditions. */
/* used only by ``comb'' and ``comib'' pseudo-ops */
save_s = s;
cmpltr = pa_parse_nonneg_cmpsub_cmpltr(&s);
if ( cmpltr < 0 ) {
s = save_s;
cmpltr = pa_parse_neg_cmpsub_cmpltr(&s);
if ( cmpltr < 0 ) {
as_bad("Unrecognized Compare/Subtract Condition: %c"
,*s);
cmpltr = 0;
}
else {
opcode |= 1 << 27; /* required opcode change to make
COMIBT into a COMIBF or a
COMBT into a COMBF or a
ADDBT into a ADDBF or a
ADDIBT into a ADDIBF */
}
}
opcode |= cmpltr << 13;
continue;
case '!': /* negated or non-negated add conditions. */
/* used only by ``addb'' and ``addib'' pseudo-ops */
save_s = s;
cmpltr = pa_parse_nonneg_add_cmpltr(&s);
if ( cmpltr < 0 ) {
s = save_s;
cmpltr = pa_parse_neg_add_cmpltr(&s);
if ( cmpltr < 0 ) {
as_bad("Unrecognized Compare/Subtract Condition: %c",
*s);
cmpltr = 0;
}
else {
opcode |= 1 << 27; /* required opcode change to make
COMIBT into a COMIBF or a
COMBT into a COMBF or a
ADDBT into a ADDBF or a
ADDIBT into a ADDIBF */
}
}
opcode |= cmpltr << 13;
continue;
case '-': /* compare/subtract conditions */
f = cmpltr = 0;
save_s = s;
if ( *s == ',' ) {
cmpltr = pa_parse_nonneg_cmpsub_cmpltr(&s);
if ( cmpltr < 0 ) {
f = 1;
s = save_s;
cmpltr = pa_parse_neg_cmpsub_cmpltr(&s);
if ( cmpltr < 0 ) {
as_bad("Unrecognized Compare/Subtract Condition");
}
}
}
opcode |= cmpltr << 13;
opcode |= f << 12;
continue;
case '+': /* non-negated add conditions */
flag = nullif = cmpltr = 0;
if ( *s == ',' ) {
s++;
name = s;
while ( *s != ',' && *s != ' ' && *s != '\t' )
s += 1;
c = *s;
*s = 0x00;
if ( strcmp(name,"=") == 0 ) {
cmpltr = 1;
}
else if ( strcmp(name,"<") == 0 ) {
cmpltr = 2;
}
else if ( strcmp(name,"<=") == 0 ) {
cmpltr = 3;
}
else if ( strcasecmp(name,"nuv") == 0 ) {
cmpltr = 4;
}
else if ( strcasecmp(name,"znv") == 0 ) {
cmpltr = 5;
}
else if ( strcasecmp(name,"sv") == 0 ) {
cmpltr = 6;
}
else if ( strcasecmp(name,"od") == 0 ) {
cmpltr = 7;
}
else if ( strcasecmp(name,"n") == 0 ) {
nullif = 1;
}
else if ( strcasecmp(name,"tr") == 0 ) {
cmpltr = 0;
flag = 1;
}
else if ( strcasecmp(name,"<>") == 0 ) {
flag = cmpltr = 1;
}
else if ( strcasecmp(name,">=") == 0 ) {
cmpltr = 2;
flag = 1;
}
else if ( strcasecmp(name,">") == 0 ) {
cmpltr = 3;
flag = 1;
}
else if ( strcasecmp(name,"uv") == 0 ) {
cmpltr = 4;
flag = 1;
}
else if ( strcasecmp(name,"vnz") == 0 ) {
cmpltr = 5;
flag = 1;
}
else if ( strcasecmp(name,"nsv") == 0 ) {
cmpltr = 6;
flag = 1;
}
else if ( strcasecmp(name,"ev") == 0 ) {
cmpltr = 7;
flag = 1;
}
else
as_bad("Unrecognized Add Condition: %s",name);
*s = c;
}
nullif = pa_parse_nullif(&s);
opcode |= nullif << 1;
opcode |= cmpltr << 13;
opcode |= flag << 12;
continue;
case '&': /* logical instruction conditions */
f = cmpltr = 0;
if ( *s == ',' ) {
s++;
name = s;
while ( *s != ',' && *s != ' ' && *s != '\t' )
s += 1;
c = *s;
*s = 0x00;
if ( strcmp(name,"=") == 0 ) {
cmpltr = 1;
}
else if ( strcmp(name,"<") == 0 ) {
cmpltr = 2;
}
else if ( strcmp(name,"<=") == 0 ) {
cmpltr = 3;
}
else if ( strcasecmp(name,"od") == 0 ) {
cmpltr = 7;
}
else if ( strcasecmp(name,"tr") == 0 ) {
cmpltr = 0;
f = 1;
}
else if ( strcmp(name,"<>") == 0 ) {
f = cmpltr = 1;
}
else if ( strcmp(name,">=") == 0 ) {
cmpltr = 2;
f = 1;
}
else if ( strcmp(name,">") == 0 ) {
cmpltr = 3;
f = 1;
}
else if ( strcasecmp(name,"ev") == 0 ) {
cmpltr = 7;
f = 1;
}
else
as_bad("Unrecognized Logical Instruction Condition:"
" %s",name);
*s = c;
}
opcode |= cmpltr << 13;
opcode |= f << 12;
continue;
case 'U': /* unit instruction conditions */
cmpltr = 0;
f = 0;
if ( *s == ',' ) {
s++;
if ( strncasecmp(s,"sbz",3) == 0 ) {
cmpltr = 2;
s += 3;
}
else if ( strncasecmp(s,"shz",3) == 0 ) {
cmpltr = 3;
s += 3;
}
else if ( strncasecmp(s,"sdc",3) == 0 ) {
cmpltr = 4;
s += 3;
}
else if ( strncasecmp(s,"sbc",3) == 0 ) {
cmpltr = 6;
s += 3;
}
else if ( strncasecmp(s,"shc",3) == 0 ) {
cmpltr = 7;
s += 3;
}
else if ( strncasecmp(s,"tr",2) == 0 ) {
cmpltr = 0;
f = 1;
s += 2;
}
else if ( strncasecmp(s,"nbz",3) == 0 ) {
cmpltr = 2;
f = 1;
s += 3;
}
else if ( strncasecmp(s,"nhz",3) == 0 ) {
cmpltr = 3;
f = 1;
s += 3;
}
else if ( strncasecmp(s,"ndc",3) == 0 ) {
cmpltr = 4;
f = 1;
s += 3;
}
else if ( strncasecmp(s,"nbc",3) == 0 ) {
cmpltr = 6;
f = 1;
s += 3;
}
else if ( strncasecmp(s,"nhc",3) == 0 ) {
cmpltr = 7;
f = 1;
s += 3;
}
else
as_bad("Unrecognized Logical Instruction Condition:"
" %c",*s);
}
opcode |= cmpltr << 13;
opcode |= f << 12;
continue;
case '>': /* shift/extract/deposit conditions. */
cmpltr = 0;
if ( *s == ',' ) {
s++;
name = s;
while ( *s != ',' && *s != ' ' && *s != '\t' )
s += 1;
c = *s;
*s = 0x00;
if ( strcmp(name,"=") == 0 ) {
cmpltr = 1;
}
else if ( strcmp(name,"<") == 0 ) {
cmpltr = 2;
}
else if ( strcasecmp(name,"od") == 0 ) {
cmpltr = 3;
}
else if ( strcasecmp(name,"tr") == 0 ) {
cmpltr = 4;
}
else if ( strcmp(name,"<>") == 0 ) {
cmpltr = 5;
}
else if ( strcmp(name,">=") == 0 ) {
cmpltr = 6;
}
else if ( strcasecmp(name,"ev") == 0 ) {
cmpltr = 7;
}
else
as_bad("Unrecognized Shift/Extract/Deposit"
"Condition: %s",name);
*s = c;
}
opcode |= cmpltr << 13;
continue;
case '~': /* bvb,bb conditions */
cmpltr = 0;
if ( *s == ',' ) {
s++;
if ( strncmp(s,"<",1) == 0 ) {
cmpltr = 2;
s++;
}
else if ( strncmp(s,">=",2) == 0 ) {
cmpltr = 6;
s += 2;
}
else
as_bad("Unrecognized Bit Branch Condition: %c",*s);
}
opcode |= cmpltr << 13;
continue;
case 'V': /* 5 bit immediate at 31 */
getExpression(s);
im5 = low_sign_unext(evaluateAbsolute(
the_insn.exp,0),5);
opcode |= im5;
s = expr_end;
continue;
case 'r': /* 5 bit immediate at 31 */
/* (unsigned value for the break instruction) */
getExpression(s);
im5 = evaluateAbsolute(the_insn.exp,0);
if ( im5 > 31 ) {
as_bad("Operand out of range. Was: %d. Should be"
"[0..31]. Assuming %d.\n",im5,im5&0x1f);
im5 = im5 & 0x1f;
}
opcode |= im5;
s = expr_end;
continue;
case 'R': /* 5 bit immediate at 15 */
/* (unsigned value for the ssm and rsm instruction) */
getExpression(s);
im5 = evaluateAbsolute(the_insn.exp,0);
if ( im5 > 31 ) {
as_bad("Operand out of range. Was: %d. Should be"
"[0..31]. Assuming %d.\n",im5,im5&0x1f);
im5 = im5 & 0x1f;
}
opcode |= im5 << 16;
s = expr_end;
continue;
case 'i': /* 11 bit immediate at 31 */
getExpression(s);
if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
im11 = low_sign_unext(evaluateAbsolute(
the_insn.exp,0),11);
opcode |= im11;
}
else {
the_insn.code = 'i';
}
s = expr_end;
continue;
case 'j': /* 14 bit immediate at 31 --- LO14 */
{
int field_selector = parse_L_or_R(s);
switch (field_selector) {
case 2: /* found the field selector R`*/
case 1: /* found the field selector L`*/
s += 2; /* eat up L` or R` */
case 0: /* not found */
getExpression(s);
break;
default:
as_bad("Bad field selector. Was: %.2s. Should be either L` or R`\n",s);
break;
}
if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
im14 = low_sign_unext(
evaluateAbsolute(the_insn.exp,field_selector), 14);
/* I donot think the mask is necessary here low_sign_unext() takes */
/* care of putting only 14 bits in im14 ! ... 090993 ... USV */
/* if (field_selector)
opcode |= (im14 & 0x7ff);
else
*/
opcode |= im14;
}
else {
the_insn.reloc = HPPA_RELOC_LO14;
the_insn.code = 'j';
}
s = expr_end;
continue;
}
case 'z': /* 17 bit branch displacement (non-pc-relative) */
/* for be, ble --- BR17*/
/* bl, ble in absence of L` or R` can have */
/* a 17 bit immmidiate number */
{
unsigned long w, w1, w2;
int field_selector = parse_L_or_R(s);
switch (field_selector) {
case 2: /* found the field selector R`*/
case 1: /* found the field selector L`*/
s += 2; /* eat up L` or R` */
case 0: /* not found */
getExpression(s);
break;
default:
as_bad("Bad field selector. Was: %.2s." "Should be either L` or R`\n",s);
break;
}
if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
im14 = sign_unext(
evaluateAbsolute(the_insn.exp,field_selector),
17);
dis_assemble_17(im14>>2,&w1,&w2,&w);
opcode |= ( ( w2 << 2 ) | ( w1 << 16 ) | w );
}
else {
the_insn.reloc = HPPA_RELOC_BR17;
the_insn.code = 'z';
}
s = expr_end;
continue;
}
case 'k': /* 21 bit immediate at 31 --- HI21 */
{
int field_selector = parse_L_or_R(s);
switch (field_selector) {
case 2: /* found the field selector R`*/
case 1: /* found the field selector L`*/
s += 2; /* eat up L` or R` */
case 0: /* not found */
getExpression(s);
break;
default:
as_bad("Bad field selector. Was: %.2s." "Should be either L` or R`\n",s);
break;
}
if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
im21 = dis_assemble_21(
(evaluateAbsolute(the_insn.exp,field_selector) >> 11));
opcode |= im21 ;
}
else {
the_insn.reloc = HPPA_RELOC_HI21;
the_insn.code = 'k';
}
s = expr_end;
continue;
}
case 'n': /* nullification for branch instructions */
nullif = pa_parse_nullif(&s);
opcode |= nullif << 1;
continue;
case 'w': /* 12 bit branch displacement */
getExpression(s);
the_insn.pcrel_reloc = 0;
the_insn.pcrel = 1;
if ( the_insn.exp.X_add_symbol ) {
if ( strcmp(
the_insn.exp.X_add_symbol->sy_nlist.n_un.n_name,"L0\001") == 0 ) {
unsigned long w1,w,result;
result = sign_unext( (the_insn.exp.X_add_number
- 8) >> 2,
12);
dis_assemble_12(result,&w1,&w);
opcode |= ( ( w1 << 2 ) | w );
}
else {
/* this has to be wrong -- dont know what is right! */
/* the_insn.reloc = R_PCREL_CALL; */
the_insn.reloc = HPPA_RELOC_12BRANCH;
the_insn.code = 'w';
}
}
else {
unsigned long w1,w,result;
result = sign_unext( the_insn.exp.X_add_number >>
2,12);
dis_assemble_12(result,&w1,&w);
opcode |= ( ( w1 << 2 ) | w );
}
s = expr_end;
continue;
case 'W': /* 17 bit branch displacement --- BL17 */
getExpression(s);
/*
* The NeXT linker has the ability to scatter
* blocks of sections between labels. This
* requires that brances to labels that survive
* to the link phase must be able to be
* relocated.
*/
if(the_insn.exp.X_add_symbol != NULL &&
(the_insn.exp.X_add_symbol->sy_name[0] != 'L'
|| flagseen['L']))
the_insn.pcrel_reloc = 1;
else
the_insn.pcrel_reloc = 0;
the_insn.pcrel = 1;
if ( the_insn.exp.X_add_symbol ) {
if ( strcmp(the_insn.exp.X_add_symbol->sy_nlist.n_un.n_name,"L0\001") == 0 ) {
unsigned long w2,w1,w,result;
result = sign_unext(
(the_insn.exp.X_add_number - 8) >> 2,17);
dis_assemble_17(result,&w1,&w2,&w);
opcode |= ( ( w2 << 2 ) | ( w1 << 16 ) | w );
}
else {
if ( (the_insn.reloc == HPPA_RELOC_JBSR) &&
(the_insn.exp.X_add_symbol->sy_name[0] != 'L') )
as_fatal("Stub label used in a JBSR must be "
"non-relocatable");
the_insn.reloc = HPPA_RELOC_BL17;
the_insn.code = 'W';
}
}
else {
unsigned long w2,w1,w,result;
result = sign_unext( the_insn.exp.X_add_number >> 2,17);
dis_assemble_17(result,&w1,&w2,&w);
opcode |= ( ( w2 << 2 ) | ( w1 << 16 ) | w );
}
s = expr_end;
continue;
case '@': /* 17 bit branch displacement --- JBSR */
getExpression(s);
/*
* assumption here is this will only be used in case of jbsr
* in which case the format is
* jbsr,n symbol,register,label
* and a relocation entry for symbol needs to be created
*/
the_insn.pcrel = 0;
the_insn.pcrel_reloc = 1;
the_insn.reloc = HPPA_RELOC_JBSR;
the_insn.code = '@';
s = expr_end;
/*
* The code to hook a frag in the chain should be here.
* Then set a flag saying that the next 'W' should not create a relocation
* entry. The way 'jbsr' is expected to work is the label will always be
* local!
* This flag should be reset in 'W'.
*/
found_jbsr = 1;
toP = frag_more(4);
fix_new(frag_now,
(toP - frag_now->fr_literal),
4,
the_insn.exp.X_add_symbol,
the_insn.exp.X_subtract_symbol,
the_insn.exp.X_add_number,
the_insn.pcrel,
the_insn.pcrel_reloc,
the_insn.reloc);
continue;
case 'B': /* either "s,b" or "b" where b & s are defined above */
reg1 = pa_parse_number(&s);
if ( *s == ',' ) {
s++;
reg2 = pa_parse_number(&s);
}
else {
reg2 = reg1;
reg1 = 0;
}
if ( reg1 < 4 && reg1 >= 0 ) {
opcode |= reg1 << 14;
opcode |= reg2 << 21;
continue;
}
break;
case 'p': /* 5 bit shift count at 26 (to support SHD instr.) */
/* value is encoded in instr. as 31-p where p is */
/* the value scanned here */
getExpression(s);
if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
opcode |= ( ( (31 - the_insn.exp.X_add_number) & 0x1f ) << 5 );
}
s = expr_end;
continue;
case 'P': /* 5-bit bit position at 26 */
getExpression(s);
if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
opcode |= ( the_insn.exp.X_add_number & 0x1f ) << 5;
}
s = expr_end;
continue;
case 'Q': /* 5 bit immediate at 10 */
/* (unsigned bit position value for the bb instruction) */
getExpression(s);
im5 = evaluateAbsolute(the_insn.exp,0);
if ( im5 > 31 ) {
as_bad("Operand out of range. Was: %d. Should be"
"[0..31]. Assuming %d.\n",im5,im5&0x1f);
im5 = im5 & 0x1f;
}
opcode |= im5 << 21;
s = expr_end;
continue;
case 'A': /* 13 bit immediate at 18 (to support BREAK instr.) */
getAbsoluteExpression(s);
if ( the_insn.exp.X_seg == SEG_ABSOLUTE )
opcode |= (the_insn.exp.X_add_number & 0x1fff) << 13;
s = expr_end;
continue;
case 'Z': /* System Control Completer(for LDA, LHA, etc.) */
if ( *s == ',' && ( *(s+1) == 'm' || *(s+1) == 'M' ) ) {
m = 1;
s += 2;
}
else
m = 0;
opcode |= m << 5;
while ( *s == ' ' || *s == '\t' ) /* skip to next operand */
s++;
continue;
case 'D': /* 26 bit immediate at 31 (to support DIAG instr.) */
/* the action (and interpretation of this operand is
implementation dependent) */
getExpression(s);
if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
opcode |= ( (evaluateAbsolute(the_insn.exp,0) & 0x1ffffff) << 1 );
}
else
as_bad("Illegal DIAG operand");
s = expr_end;
continue;
case 'f': /* 3 bit Special Function Unit (SFU) identifier at 25 */
sfu = pa_parse_number(&s);
if ( (sfu > 7) || (sfu < 0) )
as_bad("Illegal SFU identifier: %02x", sfu);
opcode |= (sfu & 7) << 6;
continue;
case 'O': /* 20 bit SFU op. split between 15 bits at 20 and 5 bits at 31 */
getExpression(s);
s = expr_end;
continue;
case 'o': /* 15 bit Special Function Unit operation at 20 */
getExpression(s);
s = expr_end;
continue;
case '2': /* 22 bit SFU op. split between 17 bits at 20
and 5 bits at 31 */
getExpression(s);
s = expr_end;
continue;
case '1': /* 15 bit SFU op. split between 10 bits at 20
and 5 bits at 31 */
getExpression(s);
s = expr_end;
continue;
case '0': /* 10 bit SFU op. split between 5 bits at 20
and 5 bits at 31 */
getExpression(s);
s = expr_end;
continue;
case 'u': /* 3 bit coprocessor unit identifier at 25 */
getExpression(s);
s = expr_end;
continue;
case 'F': /* Source FP Operand Format Completer (2 bits at 20) */
f = pa_parse_fp_format(&s);
opcode |= (int)f << 11;
the_insn.fpof1 = f;
continue;
case 'G': /* Destination FP Operand Format Completer (2 bits at 18) */
s--; /* need to pass the previous comma to pa_parse_fp_format */
f = pa_parse_fp_format(&s);
opcode |= (int)f << 13;
the_insn.fpof2 = f;
continue;
case 'M': /* FP Compare Conditions (encoded as 5 bits at 31) */
cond = pa_parse_fp_cmp_cond(&s);
opcode |= cond;
continue;
case 'v': /* a 't' type extended to handle L/R register halves. */
{
struct pa_89_fp_reg_struct result;
pa_89_parse_number(&s,&result);
if ( result.number_part < 32 && result.number_part >= 0 ) {
opcode |= (result.number_part & 0x1f);
/* 0x30 opcodes are FP arithmetic operation opcodes */
/* load/store FP opcodes do not get converted to 0x38 */
/* opcodes like the 0x30 opcodes do */
if ( need_89_opcode(&the_insn,&result) ) {
if ( (opcode & 0xfc000000) == 0x30000000 ) {
opcode |= (result.L_R_select & 1) << 6;
opcode |= 1 << 27;
}
else {
opcode |= (result.L_R_select & 1) << 6;
}
}
continue;
}
}
break;
case 'E': /* a 'b' type extended to handle L/R register halves. */
{
struct pa_89_fp_reg_struct result;
pa_89_parse_number(&s,&result);
if ( result.number_part < 32 && result.number_part >= 0 ) {
opcode |= (result.number_part & 0x1f) << 21;
if ( need_89_opcode(&the_insn,&result) ) {
opcode |= (result.L_R_select & 1) << 7;
opcode |= 1 << 27;
}
continue;
}
}
break;
case 'X': /* an 'x' type extended to handle L/R register halves. */
{
struct pa_89_fp_reg_struct result;
pa_89_parse_number(&s,&result);
if ( result.number_part < 32 && result.number_part >= 0 ) {
opcode |= (result.number_part & 0x1f) << 16;
if ( need_89_opcode(&the_insn,&result) ) {
opcode |= (result.L_R_select & 1) << 12;
opcode |= 1 << 27;
}
continue;
}
}
break;
case '4': /* 5 bit register field at 10
(used in 'fmpyadd' and 'fmpysub') */
{
struct pa_89_fp_reg_struct result;
int status;
status = pa_89_parse_number(&s,&result);
if ( result.number_part < 32 && result.number_part >= 0 ) {
if ( the_insn.fpof1 == SGL ) {
result.number_part &= 0xF;
result.number_part |= (result.L_R_select & 1) << 4;
}
opcode |= result.number_part << 21;
continue;
}
}
break;
case '6': /* 5 bit register field at 15
(used in 'fmpyadd' and 'fmpysub') */
{
struct pa_89_fp_reg_struct result;
int status;
status = pa_89_parse_number(&s,&result);
if ( result.number_part < 32 && result.number_part >= 0 ) {
if ( the_insn.fpof1 == SGL ) {
result.number_part &= 0xF;
result.number_part |= (result.L_R_select & 1) << 4;
}
opcode |= result.number_part << 16;
continue;
}
}
break;
case '7': /* 5 bit register field at 31
(used in 'fmpyadd' and 'fmpysub') */
{
struct pa_89_fp_reg_struct result;
int status;
status = pa_89_parse_number(&s,&result);
if ( result.number_part < 32 && result.number_part >= 0 ) {
if ( the_insn.fpof1 == SGL ) {
result.number_part &= 0xF;
result.number_part |= (result.L_R_select & 1) << 4;
}
opcode |= result.number_part;
continue;
}
}
break;
case '8': /* 5 bit register field at 20
(used in 'fmpyadd' and 'fmpysub') */
{
struct pa_89_fp_reg_struct result;
int status;
status = pa_89_parse_number(&s,&result);
if ( result.number_part < 32 && result.number_part >= 0 ) {
if ( the_insn.fpof1 == SGL ) {
result.number_part &= 0xF;
result.number_part |= (result.L_R_select & 1) << 4;
}
opcode |= result.number_part << 11;
continue;
}
}
break;
case '9': /* 5 bit register field at 25
(used in 'fmpyadd' and 'fmpysub') */
{
struct pa_89_fp_reg_struct result;
int status;
status = pa_89_parse_number(&s,&result);
if ( result.number_part < 32 && result.number_part >= 0 ) {
if ( the_insn.fpof1 == SGL ) {
result.number_part &= 0xF;
result.number_part |= (result.L_R_select & 1) << 4;
}
opcode |= result.number_part << 6;
continue;
}
}
break;
case 'H': /* Floating Point Operand Format at 26 for */
/* 'fmpyadd' and 'fmpysub' (very similar to 'F') */
/* bits are switched from other FP Operand */
/* formats. 1=SGL, 1=<none>, 0=DBL */
f = pa_parse_fp_format(&s);
switch (f) {
case SGL:
opcode |= 0x20;
case DBL:
the_insn.fpof1 = f;
continue;
case QUAD:
case ILLEGAL_FMT:
default:
as_bad("Illegal Floating Point Operand Format for"
"this instruction: '%s'",s);
}
break;
case 'y' : /* nullify at 26 */
nullif = pa_parse_nullif(&s);
opcode |= nullif << 5;
continue;
/* bug #41317 .... umeshv@NeXT.com Mon May 2 17:53:29 PDT 1994
These are for 'cache control hints'
l Store Instruction Cache Control Hint (Table 5-8) with
Short displacement load and store completers (Table 5-11)
L Load and Clear Word Cache Control Hint (Table 5-9) with
Indexed load completers (Table 5-10)
3 Store Instruction Cache Control Hint (Table 5-8) with
Indexed load completers (Table 5-10)
a Load and Clear Word Cache Control Hint (Table 5-9) with
Short displacement load and store completers (Table 5-11)
These parse ",cc" and encode "cc" in 2 bits at 20,
where "cc" encoding is as given in Tables 5-8, 5-9.
Refer to 'PA-RISC 1.1 Architecture and Instruction Set Reference
Manual, Second Edition' for the tables.
*/
case 'l' : /* Store Instruction Cache Control Hint */
/* Short displacement load and store completers */
opcode |= parse_completer_with_cache_control_hint(&s, 0, 'C');
continue;
case 'L' : /* Load and Clear Word Cache Control Hint */
/* Indexed load completers */
opcode |= parse_completer_with_cache_control_hint(&s, 1, 'c');
continue;
case '3' : /* Store Instruction Cache Control Hint */
/* Indexed load completers */
opcode |= parse_completer_with_cache_control_hint(&s, 0, 'c');
continue;
case 'a' : /* Load and Clear Word Cache Control Hint */
/* Short displacement load and store completers */
opcode |= parse_completer_with_cache_control_hint(&s, 1, 'C');
continue;
default:
abort();
}
break;
}
if (match == FALSE)
{
/* Args don't match. */
if (&insn[1] - pa_opcodes < NUMOPCODES
&& !strcmp(insn->name, insn[1].name))
{
++insn;
s = argsStart;
continue;
}
else
{
as_bad("Illegal operands");
return;
}
}
break;
}
the_insn.opcode = opcode;
return;
} /* end pa_ip() */
/*
This is identical to the md_atof in m68k.c. I think this is right,
but I'm not sure.
Turn a string in input_line_pointer into a floating point constant of type
type, and store the appropriate bytes in *litP. The number of LITTLENUMS
emitted is stored in *sizeP . An error message is returned, or NULL on OK.
*/
/* Equal to MAX_PRECISION in atof-ieee.c */
#define MAX_LITTLENUMS 6
char *
md_atof(
int type,
char *litP,
int *sizeP)
{
int prec;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
LITTLENUM_TYPE *wordP;
char *t;
char *atof_ieee();
switch(type) {
case 'f':
case 'F':
case 's':
case 'S':
prec = 2;
break;
case 'd':
case 'D':
case 'r':
case 'R':
prec = 4;
break;
case 'x':
case 'X':
prec = 6;
break;
case 'p':
case 'P':
prec = 6;
break;
default:
*sizeP=0;
return "Bad call to MD_ATOF()";
}
t=atof_ieee(input_line_pointer,type,words);
if(t)
input_line_pointer=t;
*sizeP=prec * sizeof(LITTLENUM_TYPE);
for(wordP=words;prec--;) {
md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
litP+=sizeof(LITTLENUM_TYPE);
}
return ""; /* Someone should teach Dean about null pointers */
}
/*
* Write out big-endian.
*/
void
md_number_to_chars(
char *buf,
long val,
int n)
{
switch(n) {
case 4:
*buf++ = val >> 24;
*buf++ = val >> 16;
case 2:
*buf++ = val >> 8;
case 1:
*buf = val;
break;
default:
abort();
}
return;
}
void
md_number_to_imm(
unsigned char *buf,
long val,
int n,
fixS *fixP,
int nsect)
{
unsigned long w1,w2,w;
unsigned new_val = 0;
unsigned long left21, right14;
if(fixP->fx_r_type == NO_RELOC ||
fixP->fx_r_type == HPPA_RELOC_VANILLA){
switch(n){
case 4:
*buf++ = val >> 24;
*buf++ = val >> 16;
case 2:
*buf++ = val >> 8;
case 1:
*buf = val;
break;
default:
abort();
}
return;
}
calc_hppa_HILO(val - fixP->fx_offset, fixP->fx_offset,
&left21, &right14);
switch (fixP->fx_r_type) {
default:
break;
/* case 'j': */
case HPPA_RELOC_LO14 :
w = low_sign_unext(right14, 14);
goto fixit;
/* case 'k': */
case HPPA_RELOC_HI21 :
w = dis_assemble_21((left21>>11));
fixit:
/* There is no guarantee that buf is word-aligned, */
/* so the adjustment must be done the hard way. */
new_val = (*buf & 0xff) << 24;
new_val |= (*(buf+1) & 0xff) << 16;
new_val |= (*(buf+2) & 0xff) << 8;
new_val |= (*(buf+3) & 0xff);
new_val |= w; /* Now, make the adjustment */
md_number_to_chars(buf,new_val,4);
break;
/* case 'W': */
case HPPA_RELOC_BL17 :
if ( !fixP->fx_addsy ) {
val -= 4; /* PA adjustment: a 0 disp is actually 4 bytes */
/* further because of the delay slot */
val >>= 2;
dis_assemble_17(val,&w1,&w2,&w);
/* There is no guarantee that buf is word-aligned, */
/* so the adjustment must be done the hard way. */
new_val = (*buf & 0xff) << 24;
new_val |= (*(buf+1) & 0xff) << 16;
new_val |= (*(buf+2) & 0xff) << 8;
new_val |= (*(buf+3) & 0xff);
new_val |= ( ( w2 << 2 ) | ( w1 << 16 ) | w );
/* Now, do the adjustment */
md_number_to_chars(buf,new_val,4);
}
else {
unsigned long result;
val -= 4; /* PA adjustment: a 0 disp is actually 4 bytes */
/* further because of the delay slot */
val >>= 2;
result = sign_unext( val,17);
dis_assemble_17(result,&w1,&w2,&w);
/* There is no guarantee that buf is word-aligned, */
/* so the adjustment must be done the hard way. */
new_val = (*buf & 0xff) << 24;
new_val |= (*(buf+1) & 0xff) << 16;
new_val |= (*(buf+2) & 0xff) << 8;
new_val |= (*(buf+3) & 0xff);
new_val |= ( ( w2 << 2 ) | ( w1 << 16 ) | w );
/* Now, do the adjustment */
md_number_to_chars(buf,new_val,4);
}
break;
/* case 'z': */
case HPPA_RELOC_BR17 :
{
unsigned long result;
right14 >>= 2;
result = sign_unext(right14,17);
dis_assemble_17(result,&w1,&w2,&w);
/* There is no guarantee that buf is word-aligned, */
/* so the adjustment must be done the hard way. */
new_val = (*buf & 0xff) << 24;
new_val |= (*(buf+1) & 0xff) << 16;
new_val |= (*(buf+2) & 0xff) << 8;
new_val |= (*(buf+3) & 0xff);
new_val |= ( ( w2 << 2 ) | ( w1 << 16 ) | w );
/* Now, do the adjustment */
md_number_to_chars(buf,new_val,4);
}
break;
/* case '@': */
case HPPA_RELOC_JBSR :
/*
* In case of the jbsr relocation no bytes are to be written to the
* output.
*
* SO DO NOTHING!
*/
break;
/* case 'w': */
/* To take care of 12 bit label */
case HPPA_RELOC_12BRANCH :
if ( !fixP->fx_addsy ) {
val -= 4; /* PA adjustment: a 0 disp is actually 4 bytes */
/* further because of the delay slot */
val >>= 2;
dis_assemble_12(val,&w1,&w);
/* There is no guarantee that buf is word-aligned, */
/* so the adjustment must be done the hard way. */
new_val = (*buf & 0xff) << 24;
new_val |= (*(buf+1) & 0xff) << 16;
new_val |= (*(buf+2) & 0xff) << 8;
new_val |= (*(buf+3) & 0xff);
new_val |= ( ( w1 << 2 ) | w ); /* Now, do the adjustment */
md_number_to_chars(buf,new_val,4);
}
else {
as_bad("Undefined symbol %s", fixP->fx_addsy->sy_name);
}
break;
}
}
void
md_convert_frag(
fragS *fragP)
{
unsigned int address;
if ( fragP -> fr_type == rs_machine_dependent ) {
switch ( (int) fragP -> fr_subtype ) {
case 0:
fragP -> fr_type = rs_fill;
know( fragP -> fr_var == 1 );
know( fragP -> fr_next );
address = fragP -> fr_address + fragP -> fr_fix;
if ( address % fragP -> fr_offset ) {
fragP -> fr_offset =
fragP -> fr_next -> fr_address
- fragP -> fr_address
- fragP -> fr_fix;
}
else
fragP -> fr_offset = 0;
break;
}
}
}
int
md_estimate_size_before_relax(
fragS *fragP,
int nsect)
{
int size;
size = 0;
while ( (fragP->fr_fix + size) % fragP->fr_offset )
size++;
return size;
}
int
md_parse_option(
char **argP,
int *cntP,
char ***vecP)
{
return 1;
}
/*
int is_end_of_statement()
{
return ( (*input_line_pointer == '\n')
|| (*input_line_pointer == ';')
|| (*input_line_pointer == '!') );
}
*/
static
int
parse_L_or_R(
char *str)
{
/* not much work done as yet! */
switch (*str) {
case '%':
case '(':
return 0; /* ie. not found */
break;
case 'L':
case 'l':
if (*(str+1) == '\'' || *(str+1) == '`') /* check next character */
return 1; /* found */
else
return 0; /* not found */
break;
case 'R':
case 'r':
if (*(str+1) == '\'' || *(str+1) == '`') /* check next character */
return 2; /* found */
else
return 0; /* not found */
break;
default: /* default is not found ... at least for the time being */
return 0;
break;
}
} /* end parse_L_or_R() */
static
unsigned long
parse_cache_control_hint(
char **s, /* Note : the function changes '*s' */
int option) /* option = 0 for store instruction */
/* option = 1 for load and clear instruction */
{
unsigned long cc = NO_CACHE_CONTROL_HINT;
if (**s == ',') {
(*s)++;
switch (option) {
case 0 : /* Store Instruction Cache Control Hint */
if ( strncasecmp(*s,"bc",2) == 0 ) {
/* BLOCK_COPY */
(*s) += 2;
cc = BC_OR_CO_CACHE_CONTROL_HINT;
/* eat up extra blanks and tabs */
while ( **s == ' ' || **s == '\t' )
(*s)++;
} else
as_fatal("Illegal Cache Control Hint: '%s'"
" - expected 'bc'",*s);
break;
case 1 : /* Load and Clear Word Cache Control Hint */
if ( strncasecmp(*s,"co",2) == 0 ) {
/* COHERENT_OPERATION */
(*s) +=2;
cc = BC_OR_CO_CACHE_CONTROL_HINT;
/* eat up extra blanks and tabs */
while ( **s == ' ' || **s == '\t' )
(*s)++;
} else
as_fatal("Illegal Cache Control Hint: '%s'"
" - expected 'co'",*s);
break;
default :
as_fatal("Invalid option (%d) for parsing cache control hints",
option);
break;
}
}
/* else NO_HINT */
/*
* the completers have already eaten up extra blanks
* and tabs. So there is no need to do that again here.
*/
return cc;
} /* end parse_cache_control_hint() */
static
unsigned long
parse_completer_with_cache_control_hint(
char **s, /* Note : the function changes '*s' */
int option, /* option = 0 for store instruction */
/* option = 1 for load and clear instruction */
char completer) /* 'c' or 'C' */
{
unsigned long i, result = (unsigned long) 0UL;
int m, a, u;
switch (completer) {
case 'c': /* indexed load completer. */
i = m = u = 0;
while ( **s == ',' && i < 3 ) {
(*s)++;
if ( strncasecmp((*s),"sm",2) == 0 ) {
m = u = 1;
(*s)++;
i++;
}
else if ( strncasecmp((*s),"m",1) == 0 )
m = 1;
else if ( strncasecmp((*s),"s",1) == 0 )
u = 1;
else if ( strncmp((*s),",",1) == 0 ) /* no completer */
result |= parse_cache_control_hint(s, option);
else if ( (strncasecmp((*s),"c",1) == 0) ||
(strncasecmp((*s),"b",1) == 0) ) {/* just 1 completer */
(*s)--;
result |= parse_cache_control_hint(s, option);
}
else
as_bad("Unrecognized Indexed Load"
"Completer with cache control hints...assuming 0");
if (result == (unsigned long)0UL)
(*s)++;
i++;
}
if ( i > 3 )
as_bad("Illegal Indexed Load Completer with cache control hints"
" Syntax... extras ignored");
while ( **s == ' ' || **s == '\t' )
(*s)++;
result |= m << 5;
result |= u << 13;
break;
case 'C': /* short load and store completer */
i = m = a = 0;
while ( **s == ',' && i < 2 ) {
(*s)++;
if ( strncasecmp((*s),"ma",2) == 0 ) {
a = 0;
m = 1;
}
else if ( strncasecmp((*s),"mb",2) == 0 ) {
m = a = 1;
}
else if ( strncmp((*s),",",1) == 0 ) /* no completer */
result |= parse_cache_control_hint(s, option);
else if ( (strncasecmp((*s),"c",1) == 0) ||
(strncasecmp((*s),"b",1) == 0) ) {/* just 1 completer */
(*s)--;
result |= parse_cache_control_hint(s, option);
}
else
as_bad("Unrecognized Indexed Load Completer"
"...assuming 0");
i++;
(*s) += 2;
}
while ( **s == ' ' || **s == '\t' )
(*s)++;
result |= m << 5;
result |= a << 13;
break;
default :
as_fatal("Invalid completer (%c) for parsing cache control hints",
completer);
break;
}
return result;
} /* end parse_completer_with_cache_control_hint() */
/* end hppa.c */